#include "RenderPass.h"
#include "RendererParams.h"

namespace Nezha
{

	u8 RenderPass::msMaxSamplersPerPass = 16;

	RenderPass::RenderPass(const _string& name)
		:mName(name)
		//:mHandle(0)
		,mCull(RSCO_CCW)
		,mFillMode(RSFM_SOLID)
	{

	}

	RenderPass::~RenderPass()
	{
		destroyParams();
	}

	bool RenderPass::begin()
	{
		// TODO

		return false;
	}

	void RenderPass::end()
	{
		// TODO
	}

	void RenderPass::destroyParams()
	{
		for(PArray<ShaderParameter*>::iterator it = mShaderParams.begin(); it != mShaderParams.end(); it++)
		{
			NZ_Delete (*it);
		}

		mShaderParams.clear();
		mSamplers.clear();
	}

	void RenderPass::setShaderParamFloat(const _string& name, float f)
	{
		ShaderParameter* sp = getParamByName(name);

		if(sp && sp->getDataType() == SPDT_FLOAT && sp->getCategory() != SPC_BUILTIN
			&& sp->getSizeInBytes() > 0)
		{
			sp->setData(f);
		}
	}

	void RenderPass::setShaderParamVector(const _string& name, const Vector3& vec)
	{
		ShaderParameter* sp = getParamByName(name);

		if(sp && sp->getDataType() == SPDT_FLOAT3 && sp->getCategory() != SPC_BUILTIN
			&& sp->getSizeInBytes() > 0)
		{
			sp->setData(vec);
		}
	}

	void RenderPass::setShaderParamVector(const _string& name, const Vector4& vec)
	{
		ShaderParameter* sp = getParamByName(name);

		if(sp && sp->getDataType() == SPDT_FLOAT4 && sp->getCategory() != SPC_BUILTIN
			&& sp->getSizeInBytes() > 0)
		{
			sp->setData(vec);
		}
	}

	void RenderPass::setShaderParamMatrix(const _string& name, const Matrix3x3& mat)
	{
		ShaderParameter* sp = getParamByName(name);

		if(sp && sp->getDataType() == SPDT_FLOAT3X3 && sp->getCategory() != SPC_BUILTIN
			&& sp->getSizeInBytes() > 0)
		{
			sp->setData(mat);
		}
	}

	void RenderPass::setShaderParamMatrix(const _string& name, const Matrix4x4& mat)
	{
		ShaderParameter* sp = getParamByName(name);

		if(sp && sp->getDataType() == SPDT_FLOAT4X4 && sp->getCategory() != SPC_BUILTIN
			&& sp->getSizeInBytes() > 0)
		{
			sp->setData(mat);
		}
	}

	void RenderPass::setProgram(const ShaderProgramPtr& program)
	{
		// TODO

		if(program == mProgram)
			return;

		destroyParams();

		u32 numParam = program->numShaderParams();

		for(u32 i = 0; i < numParam; i++)
		{
			const ShaderParamDesc& desc = program->getParamDesc(i);
			
			switch(desc.Category)
			{
			case SPC_BUILTIN:
				{
					RendererParam* rp = NZ_New RendererParam();
					rp->create(RendererParam::NameToType(desc.Name));
					mShaderParams.push_back(static_cast<ShaderParameter*>(rp));
				}
				break;
			case SPC_APP:
				{
					ShaderParamApp* spa = NZ_New ShaderParamApp(desc.Name, desc.DataType);
					mShaderParams.push_back(static_cast<ShaderParameter*>(spa));
				}
				break;
			case SPC_SAMPLER:
				{
					ShaderSampler* ss = NZ_New ShaderSampler();
					mShaderParams.push_back(static_cast<ShaderParameter*>(ss));
					mSamplers.push_back(ss);
				}
				break;
			}
		}

		mProgram = program;
	}

	void RenderPass::copyRenderStatesFrom(const RenderPass* pass)
	{
		mBlending = pass->mBlending;
		mDepth = pass->mDepth;
		mOffset = pass->mOffset;
		mStencil = pass->mStencil;
		mCull = pass->mCull;
		mFillMode = pass->mFillMode;
		mColorMask = pass->mColorMask;	
	}

	ShaderParameter* RenderPass::getParam(u32 i)
	{
		NZ_ASSERT(i < mShaderParams.size());

		return mShaderParams[i];	
	}

	ShaderSampler* RenderPass::getSamper(u32 i)
	{
		NZ_ASSERT(i < mSamplers.size());

		return mSamplers[i];
	}

	ShaderParameter* RenderPass::getParamByName(const _string& name)
	{
		for(PArray<ShaderParameter*>::iterator it = mShaderParams.begin(); it != mShaderParams.end(); it++)
		{
			if((*it)->getName() == name)
			{
				return (*it);
			}
		}

		return NULL;
	}

	void RenderPass::_SetMaxSamplersPerPass(u8 num)
	{
		msMaxSamplersPerPass = num;
	}

}//end namespace Nezha